home *** CD-ROM | disk | FTP | other *** search
- ;==========================================================================;
- ; 8250 and QuardRam Quadport Interrupt handler ;
- ; ;
- ; Copyright 1983 by William E. Westfield. All rights reserved. ;
- ; Copyright 1986, 1988,1990 by H. Roy Engehausen. All rights reserved. ;
- ; This software may be freely distributed and used, but it may not ;
- ; under any circumstances be sold by anyone other than the author. ;
- ; It may be distributed by a commercial company as long as it is ;
- ; for no cost. ;
- ;==========================================================================;
-
- IF present_qrqp OR present_4apc
-
- CMP chip[SI],chip_8250 ; 8250?
- JE serint_qrqp_not ; Yep....
-
- ;--------------------------------------------------------------------------;
- ; This outside loop is for the QuadPort board or the 4 async port ;
- ; card. We loop thru all the ports checking for pending interrupts ;
- ; and handling them. There is a catch at the far end which loops us ;
- ; back. Other than that, there are no changes. ;
- ; ;
- ; The only difference between the QUADRAN QUADPORT card and the 4 async ;
- ; port card is that the QuadPort card has an extra register for interrupt ;
- ; control. ;
- ;--------------------------------------------------------------------------;
-
- CMP chip[SI],chip_qrqp ; Quadram QuadPort?
- JNE serint_qrqp_do ; Nope.. go directly to loop.
- ; This happens for the 4 async port
-
- ;--------------------------------------------------------------------------;
- ; Get the Master Interrupt ID register.... If nothing to do then quit ;
- ;--------------------------------------------------------------------------;
-
- AND DL,basem_qrqp ; Now get the board base address
- ADD DX,qintr_qrpt ; Point to master interrupt register
- IN AL,DX ; and read it...
- AND AL,00011111B ; Remove unnecessary bits
- ; JNZ serint_qrqp_do ; We have something to do
- ; JMP serint_qrqp_gobye ; Nothing here! Leave...
-
- serint_qrqp_do:
-
- ;--------------------------------------------------------------------------;
- ; Get ready to loop ;
- ;--------------------------------------------------------------------------;
-
- MOV qrqp_tie_pointer,0 ; Pointer to tie pointer to service next
-
- ;--------------------------------------------------------------------------;
- ; Here is the loop... AL contains the MIR and SI points to one of the ;
- ; com blocks to get here ;
- ;--------------------------------------------------------------------------;
-
- serint_qrqp_loop:
-
- MOV DI,chip_comm[SI] ; Where is the tie block?
- MOV CX,qrqp_tie_pointer ; Pointer to tie pointer to service next
-
- CMP chip[SI],chip_qrqp ; Quadram QuadPort?
- JNE serint_qrqp_more ; Nope.. keep going....
-
- CMP CX,max_port_qrqp*2 ; Are we at the end?
- JL serint_qrqp_more ; Nope.. keep going....
- JMP serint_qrqp_exit ; Yep... Time to go
-
- serint_qrqp_more:
-
- ;--------------------------------------------------------------------------;
- ; Now we increment the pointer for the next time thru (if any) ;
- ;--------------------------------------------------------------------------;
-
- ADD DI,CX ; Add the offset so we can find the block
- INC CX ; Bump the pointer to the next ptr in tie
- INC CX ; block (2 for words)
- MOV qrqp_tie_pointer,CX ; Save pointer for next time around
-
- ;--------------------------------------------------------------------------;
- ; Fetch the comm block address. If it exists, we continue normally ;
- ; If not, then: ;
- ; 1) On a QUADRAM QUADPORT card, this is not our channel. We skip it ;
- ; and go to the next one. The order in the tie block is important ;
- ; because the entries are in the same order as the master interrupt ;
- ; register ;
- ; 2) On a 4 async port card, this signifies the end of the list. ;
- ;--------------------------------------------------------------------------;
-
- MOV CX,WORD PTR [DI] ; Get the comm block
- OR CX,CX ; Is there one?
- JNZ serint_qrqp_okblock ; Yep.. Lets do it
-
- CMP chip[SI],chip_qrqp ; Quadram QuadPort?
- JE serint_qrqp_loop ; Yep.. Loop again to ignore this port
-
- JMP serint_4apc_exit ; 4 async port card exit
-
- serint_qrqp_okblock:
-
- MOV SI,CX ; Put the address in the right place
-
- ;--------------------------------------------------------------------------;
- ; See if this is the QuadPort card and, therefore, contains a master ;
- ; interrupt register to check. If not, keep going.... ;
- ;--------------------------------------------------------------------------;
-
- CMP chip[SI],chip_qrqp ; Quadram QuadPort?
- JNE serint_4apc_do ; Nope.. go directly to loop.
-
- ;--------------------------------------------------------------------------;
- ; Each bit in the MIR corresponds to one chip on the board so we will ;
- ; see if the chip whose com block I am looking at wants service ;
- ;--------------------------------------------------------------------------;
-
- SHR AL,1 ; Shift the MIR one right putting the low
- ; order bit it the carry register
- ; JNB serint_qrqp_loop ; Carry bit is off, this chip does not
- ; want to be serviced...
-
- ; This use to be below the label
- MOV qrqp_save_mir,AL ; Save the shifted master interrupt register
-
- ;--------------------------------------------------------------------------;
- ; We now have a port who wants something. We now set the registers as ;
- ; if this is a regular 8250 and let the normal interrupt handler ;
- ; do its work. ;
- ;--------------------------------------------------------------------------;
-
- serint_4apc_do:
-
- MOV serint_4apc_switch,0 ; Clear the interrupt handled switch
-
- MOV DX,baseaddr[SI] ; Get the base port address
-
- ; End QuadRam QuadPort board handler start
-
- serint_qrqp_not: ; Used for real 8250s to skip everything
-
- ENDIF
-
- MOV CX,DX ; Save the port address
-
- ;--------------------------------------------------------------------------;
- ; Get the IIR to identify the cause ;
- ;--------------------------------------------------------------------------;
-
- ADD DX,iir_8250 ; Get the IIR
- IN AL,DX ;
-
- ;--------------------------------------------------------------------------;
- ; If no interrupt pending on this channel, skip it. ;
- ;--------------------------------------------------------------------------;
-
- AND AL,iir_8250_ip ; Interrupt pending?
- ; V3.2 attempts un-nooped the next two instructions
- JZ serint_8250_do ; Yep...
- JMP serint_8250_exit ; No leave...
-
- ;==========================================================================;
- ; This is the place we come to when we want to service the chip ;
- ;==========================================================================;
-
- serint_8250_do:
-
- ;--------------------------------------------------------------------------;
- ; Get the LSR ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,CX ; Get the LSR
- ADD DX,lsr_8250 ;
- IN AL,DX ;
-
- ;==========================================================================;
- ; This label is used when the LSR is already loaded ;
- ;==========================================================================;
-
- serint_8250_int_loop:
-
- ;--------------------------------------------------------------------------;
- ; Save the LSR by oring into the status block ;
- ;--------------------------------------------------------------------------;
-
- AND last_rs[SI],0FFH-lsr_8250_thre ; Remove THRE
- OR last_rs[SI],AL ; And tuck it away
-
- ;==========================================================================;
- ; Receive Data Available handler ;
- ;==========================================================================;
-
- TEST AL,lsr_8250_dr ; RDA on?
- JZ serint_8250_norda ; No receive data available
-
- IF present_4apc
- MOV serint_4apc_switch,1 ; Set the interrupt handled switch
- ENDIF
-
- ;--------------------------------------------------------------------------;
- ; Get the data ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,CX ; Get the RBR
- ; ADD DX,rbr_8250 ; This is zero so we don't do it...
- IN AL,DX ;
-
- ;--------------------------------------------------------------------------;
- ; Take the data we just got and stuff it into the buffer ;
- ;--------------------------------------------------------------------------;
-
- MOV DI,buffer_r_in[SI] ; Get the buffer pointer
- MOV DX,ES ; Gotta use ES so save it
- MOV ES,buffer_r_a[SI] ; Get buffer's segment
- MOV ES:[DI],AL ; Save the character
- MOV ES,DX ; All done with ES so put it back
-
- ;--------------------------------------------------------------------------;
- ; Bump pointer and handle wrapping around the end of the buffer ;
- ;--------------------------------------------------------------------------;
-
- INC DI ; Bump pointer and handle wrap
- CMP DI,buffer_size ;
- JL serint_8250_nowrap ;
- SUB DI,DI ;
- serint_8250_nowrap:
-
- ;--------------------------------------------------------------------------;
- ; See if we are about try to store into a buffer position that hasn't ;
- ; been emptied yet. If this occurs, don't bump the pointer but signal ;
- ; overflow instead ;
- ;--------------------------------------------------------------------------;
-
- CMP DI,buffer_r_out[SI] ; Overflow of buffer?
- JNE serint_8250_noover ;
- OR last_rs[SI],lsr_8250_or ; Overrun indicate
- JMP SHORT serint_8250_over ; Don't save the updated pointer
- serint_8250_noover:
- MOV buffer_r_in[SI],DI ; Save the updated pointer
- serint_8250_over:
-
- ;--------------------------------------------------------------------------;
- ; If we have hardware handshaking enabled, then see if we need to ;
- ; signal stop. We will use 1/16 of a buffer as a limit ;
- ;--------------------------------------------------------------------------;
-
- TEST options[SI],opt_hdwhs ; Hardware handshaking desired?
- JZ serint_8250_r_nostop ; Nope
-
- SUB DI,buffer_r_out[SI] ; Compute the delta
- JG serint_8250_rpos ; Jump over if positive result
- ADD DI,buffer_size ; This will convert it back to positive
- serint_8250_rpos: ; DI now is equal to bytes used!
-
- CMP DI,(buffer_size * 15) / 16 ; See if at least 1/16 is left
- JLE serint_8250_r_nostop ; Yes.. No stop needed
-
- MOV DX,CX ; Get the MCR
- ADD DX,mcr_8250 ;
- MOV AL,hoff_8250 ; Turn off sending from distant end
- OUT DX,AL ;
-
- serint_8250_r_nostop:
-
- ;--------------------------------------------------------------------------;
- ; Finished with receive data interrupt ;
- ;--------------------------------------------------------------------------;
-
- serint_8250_norda: ; No receive data available
-
- ;==========================================================================;
- ; Transmit Holding Buffer Empty handler ;
- ;==========================================================================;
-
- ;--------------------------------------------------------------------------;
- ; Read the MSR.. We always do this to clear any pending modem status ;
- ; change interrupt ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,CX ; Compute port address for the MSR
- ADD DX,msr_8250 ;
- IN AL,DX ; Get the MSR into AL
-
- ;--------------------------------------------------------------------------;
- ; Now look at the THRE. If its not on, ignore all of this ;
- ;--------------------------------------------------------------------------;
-
- TEST last_rs[SI],lsr_8250_thre ; Transmit holding register empty ?
- JZ serint_8250_nothre ; Nope
-
- ;--------------------------------------------------------------------------;
- ; See if anything to be sent. Note... If transmit buffering is not ;
- ; selected for this channel, this will never be true. Save us from ;
- ; having to check the options field ;
- ;--------------------------------------------------------------------------;
-
- MOV DI,buffer_t_out[SI] ; Get buffer output pointer
- CMP DI,buffer_t_in[SI] ; See where the in pointer is
- JE serint_8250_nothre ; If they are not equal then we have
- ; data in the buffer
-
- ;--------------------------------------------------------------------------;
- ; Worry about hardware handshaking as appropriate. ;
- ;--------------------------------------------------------------------------;
-
- TEST options[SI],opt_hdwhs ; Hardware handshaking desired?
- JZ serint_8250_thre_nohw ; Nope..
-
- ; Check the previously loaded MSR
- AND AL,msr_8250_cts ; CTS on?
- JNZ serint_8250_thre_nohw ; Yep, send something
-
- OR flags[SI],flags_xmt_h ; Show transmitter is held
- JMP serint_8250_nothre ; Don't do anything else
-
- serint_8250_thre_nohw:
-
- ;--------------------------------------------------------------------------;
- ; Ok we have something to send and all the indicators are go!!! ;
- ;--------------------------------------------------------------------------;
-
- AND flags[SI],0FFH-flags_xmt_h ; Remove transmitter held flag
-
- MOV DX,ES ; Gotta use ES so save it
- MOV ES,buffer_t_a[SI] ; Get buffer's segment
- MOV AL,ES:[DI] ; Save the character
- MOV ES,DX ; All done with ES so put it back
-
- MOV DX,CX ; Compute port address for the THR
- ; ADD DX,thr_8250 ; and then
- OUT DX,AL ; out the character
- ; The add of THR is commented out since the THR is at zero from
- ; the base. This just documents the fact we are going for the THR
-
- ;--------------------------------------------------------------------------;
- ; Turn on the character sent flag ;
- ;--------------------------------------------------------------------------;
-
- OR flags[SI],flags_xmt_on ; Turn on transmitter flag
-
- ;--------------------------------------------------------------------------;
- ; Bump pointer and handler wrap condition ;
- ;--------------------------------------------------------------------------;
-
- INC DI ; Bump pointer and handle wrap
- CMP DI,buffer_size ;
- JL serint_8250_nothrewrap ;
- SUB DI,DI ;
- serint_8250_nothrewrap:
-
- MOV buffer_t_out[SI],DI ; Save buffer output pointer
-
- ;--------------------------------------------------------------------------;
- ; Finished with transmit holding buffer empty interrupt ;
- ;--------------------------------------------------------------------------;
-
- IF present_4apc
- MOV serint_4apc_switch,1 ; Set the interrupt handled switch
- ENDIF
-
- serint_8250_nothre:
-
- ;==========================================================================;
- ; Exit interrupt handler when we have done something ;
- ;==========================================================================;
-
- MOV AL,pic_clear ; Tell 8259 we are done
-
- TEST options[SI],opt_high_irq ; Slave 8259 involved?
- JZ serint_8250_pic_master ; Nope
-
- OUT pic2_cmd_port,AL ; Clear slave
-
- serint_8250_pic_master:
-
- OUT pic_cmd_port,AL ; Clear master
-
- ;--------------------------------------------------------------------------;
- ; If interrupt pending on this channel still, go back and do it ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,CX ;
- ADD DX,iir_8250 ; Get the IIR
- IN AL,DX ;
-
- AND AL,iir_8250_ip ; Interrupt pending?
- JNZ serint_8250_noip ; Nope.. Go to common exit routine
-
- IF present_4apc
- MOV serint_4apc_switch,1 ; Set the interrupt handled switch
- ENDIF
-
- JMP serint_8250_do ; Yep... Loop back
-
- serint_8250_noip:
-
- ;==========================================================================;
- ; Exit Interrupt handler ;
- ;==========================================================================;
-
- serint_8250_exit:
-
- IF present_qrqp OR present_4apc
-
- CMP chip[SI],chip_8250 ; Plain old 8250?
- JE serint_qrqp_gobye ; Yep.....
-
- CMP chip[SI],chip_4apc ; Four Async port card
- JNE serint_qrqp_byechk ; Nope... Must be quadram
-
- ;--------------------------------------------------------------------------;
- ; This is the end of interrupt handler for the 4 async port card ;
- ; It works on the premise that if we handled any interrupts we will ;
- ; have to repoll everyone to ensure that at some instant, all the ;
- ; interrupts were cleared. We do this by forcing the pointer to the ;
- ; port under test back to the beginning of the list ;
- ;--------------------------------------------------------------------------;
-
-
- CMP serint_4apc_switch,0 ; Set the interrupt handled switch
- JE serint_4apc_noint ;
-
- MOV qrqp_tie_pointer,0 ; Pointer to tie pointer to service next
-
- serint_4apc_noint:
-
- JMP serint_qrqp_loop ; Loop
-
- ;--------------------------------------------------------------------------;
- ; This is the end of interrupt handler for the QUADRAM QuadPort card ;
- ;--------------------------------------------------------------------------;
-
- serint_qrqp_byechk:
-
- ;--------------------------------------------------------------------------;
- ; This code loops back to the top of the interrupt handler if this is ;
- ; a QuadRam Quadport board with more to do ;
- ;--------------------------------------------------------------------------;
-
- CMP chip[SI],chip_qrqp ; QUADRAM QUADPORT card?
- JNE serint_qrqp_goback ; Nope.... Force return
-
- MOV AL,qrqp_save_mir ; Get the shifted master interrupt register
- OR AL,AL ; Anything left to do?
- JZ serint_qrqp_exit ; Nope....
- serint_qrqp_goback:
- JMP serint_qrqp_loop ; Yep.....
-
- ;--------------------------------------------------------------------------;
- ; QUADRAM QuadPort card exit routine ;
- ;--------------------------------------------------------------------------;
-
- serint_qrqp_exit:
-
- ;--------------------------------------------------------------------------;
- ; Clear the master interrupt register ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,baseaddr[SI] ; Get the base port address
- AND DL,basem_qrqp ; Now get the board base address
- ADD DX,qintr_qrpt ; Point to master interrupt register
-
- MOV AL,hiv[SI] ; Get the hardware interrupt vector number
-
- CMP AL,irq2_offset ; Convert it to IRQ number
- JL serint_qrqp_exit2 ;
- SUB AL,irq2_offset-8 ;
- JMP SHORT serint_qrqp_exit3;
- serint_qrqp_exit2:
- SUB AL,irq_offset ;
- serint_qrqp_exit3:
-
- CBW ;
- MOV DI,AX ; Make into an index
- MOV AL,qrqp_int_map[DI] ; Get the proper setting for the vector
- OUT DX,AL ; And send it
-
- ;--------------------------------------------------------------------------;
- ; See if there is anything left to do ;
- ;--------------------------------------------------------------------------;
-
- IN AL,DX ; and read it...
- AND AL,00011111B ; Remove unnecessary bits
- JZ serint_qrqp_gobye ; We have nothing to do
- JMP serint_qrqp_do ; We have something to do
-
- serint_qrqp_gobye:
-
- ENDIF
-
- ;--------------------------------------------------------------------------;
- ; We come here when all the interrupts are clear on a 4 async port card ;
- ;--------------------------------------------------------------------------;
-
- serint_4apc_exit:
-
- ;--------------------------------------------------------------------------;
- ; Clear the system interrupt! ;
- ;--------------------------------------------------------------------------;
-
- JMP serint_exit ; Go to common exit routine
-